//
// Created by Soar Qin on 2017/8/22.
// Copyright (c) 2017 Soar Qin. All rights reserved.
//

#include "common.hh"

#include "tcp_listener.hh"
#include "loop.hh"
#include "ip_addr.hh"
#include "tcp_endpoint.hh"

#include "private/tcp_listener_private.hh"
#include "private/loop_private.hh"

namespace core::async {

void listenercb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr, int socklen, void *arg) {
    (void) listener;
    auto *ls = static_cast<TCPListener*>(arg);
    if (!ls->onAccept((int)fd))
        evutil_closesocket(fd);
}

void listenererrcb(struct evconnlistener *listener, void *arg) {
    (void) listener;
    (void) arg;
}

TCPListener::TCPListener(Loop &loop): IoBase(loop), context_(new TcpListenerContext) {
}

TCPListener::~TCPListener() {
    if (context_->listener != nullptr)
        evconnlistener_free(context_->listener);
    delete context_;
}

bool TCPListener::listen(const IPAddr &addr) {
    if (!addr.ok()) return false;
    int socklen;
    auto *sockaddr = addr.getAddr(socklen);
    context_->listener = evconnlistener_new_bind(loop_.getContext()->evbase, listenercb, this, LEV_OPT_CLOSE_ON_FREE, -1, sockaddr, socklen);
    if (context_->listener == nullptr) return false;
    evconnlistener_set_error_cb(context_->listener, listenererrcb);
    return true;
}

bool TCPListener::listen(const std::string &address) {
    return listen(IPAddr(address));
}

bool TCPListener::listen(const std::string &ip, uint16_t port) {
    return listen(IPAddr(ip, port));
}

}
